package fem2d;

import math2.FunctionBasisOnRnToR;
import fem2.AbstractStructuralStaticDemo;
import fem2.Constraint;
import fem2.Debugger;
import fem2.Element;
import fem2.Face;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshGenerator;
import fem2.MeshPart;
import fem2.MeshUtilities;
import fem2.Model;
import fem2.Node;
import fem2.Observer;
import fem2.StringUtilities;
import fem2.Topology;
import fem2.analysis.Analysis;
import fem2.element.StructuralElement;
import fem2.enu.EchoLevelType;
import fem2.enu.State;
import fem2.level_set.Crack;
import fem2.material.StVenantKirchhoffMM;
import fem2.observer.GidDisplacementObserver;
import fem2.observer.TimeStepObserver;
import fem2.observer.TimingObserver;
import fem2.observer.XfemManager;
import fem2.pre_and_post.GidMeshGenerator;
import fem2.pre_and_post.GidPostStructural;
import fem2.strategies.NonAdaptiveNewtonRaphsonStrategyForXfem;
import fem2.strategies.Strategy;

public class LshapeXfem extends AbstractStructuralStaticDemo {

	public LshapeXfem() {
		projectDir = "/home/hbui/kratos_janosch";
		projectName = "Lshape.gid";
		meshFileName = "q4mesh1-xfem.msh";
	}

	@Override
	public Mesh createMesh() {
		String fn = projectDir + '/' + projectName + '/' + meshFileName;
		MeshGenerator mg = new GidMeshGenerator(fn);
		Mesh mesh = mg.getMesh(2);
		return mesh;
	}

	@Override
	public Model createConditions(Model m) {
		Mesh mesh = m.getMesh();
		Constraint c1 = new Constraint(false, false);
		Constraint c2 = new Constraint(true, false);
		double du = -0.01;
		c2.setValue(1, du);
		mesh.setConstraint(c1, MeshUtilities.seekNodesOnSurface(mesh, 0, 1, -1000));
		MeshUtilities.seekNode(mesh, 1000, 500).setConstraint(c2);
		return m;
	}

	@Override
	public MaterialModel createMaterial(Model m) {
		double E = 25850;
		double nu = 0.18;
		double t = 200;
		State ss = State.PLANE_STRESS;
		MaterialModel mm = new StVenantKirchhoffMM(E, nu, t, 0, ss);
		return mm;
	}

	@Override
	public Element createElement(MeshPart mp, MaterialModel mm) {
		return new StructuralElement(mp, mm);
	}

	@Override
	protected void addFundamentalObservers(Model m, Strategy s, TimeStepObserver o) throws Error {
		if (meshFileName == null) {
			throw new Error("mesh file name was not set");
		}

		/*
		 * clean all previous post files
		 */
		String meshName = StringUtilities.getFileName(meshFileName);

		GidPostStructural post = new GidPostStructural(projectDir, projectName, meshName);
		post.clearAllPostFiles();

		Observer do1 = new GidDisplacementObserver(m, o, projectDir, projectName, meshName);

		s.addObserver(do1);
		s.addObserver(new TimingObserver());
	}

	@Override
	public void run(int nt) {
		Model m = createModel();

		Topology to = new Topology(m);
		m.getMesh().setTopology(to);

		Analysis an = new Analysis(m);
		an.setStrategy(new NonAdaptiveNewtonRaphsonStrategyForXfem(m, nt));
		Strategy s = an.getStrategy();
		s.setEchoLevel(EchoLevelType.OUTPUT, EchoLevelType.AUX1);

		double[] tip_start = new double[] { 500.0, 510.0 };
		double[] tip_delta = new double[] { -93.0, -81.0 };
		// double[] tip_delta = new double[] { -30.0, -30.0 };
		// double[] tip_delta = new double[] { -93.0, -105.0 };

		Crack c = new Crack(m, tip_start, tip_delta);
		c.setJIntegralRadius(250.0);
		c.setPropagationStep(20.0);

		XfemManager x = new XfemManager(m);

		x.addCrack(c);

		s.addObserver(x);

		addFundamentalObservers(m, s, new TimeStepObserver(s));

		an.run();

		postProcess(m);

		Node n0 = m.getMesh().getNode(0);
		Debugger.watch(n0.getUHatLocal());

		Face f = m.getMesh().getFace(0);
		double[] uh = f.getUHatLocal();
		FunctionBasisOnRnToR basis = f.getBasis();
		double[] u0 = new double[2];
		for (int i = 0; i < basis.getDimension(); i++) {
			u0[0] += basis.getBasisFunction(i).valueAt(-1, -1) * uh[2 * i];
			u0[1] += basis.getBasisFunction(i).valueAt(-1, -1) * uh[2 * i + 1];
		}
		Debugger.watch(u0);

		Debugger.warn("Analysis completed");
	}

	public static void main(String[] args) {
		AbstractStructuralStaticDemo demo = new LshapeXfem();

		demo.run(20);
	}
}
